home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d19 / cal14s5.arc / CALLS.PAS < prev    next >
Pascal/Delphi Source File  |  1988-11-09  |  60KB  |  2,118 lines

  1.  
  2. {$M 50000,30000,500000}  {Stack, minheap, maxheap}
  3.  
  4. {$L-}    {Don't link in ram}
  5. {$T+}    {Make mapfile}
  6. {$S-}    {Stack testing}
  7. {$R-}    {Range checks}
  8. {$V-}    {Relax string rules}
  9.  
  10. program callers;
  11.  
  12. uses dos, bufio, crt;
  13.  
  14.  
  15. {                 PCBoard Call Analyzer Ver. 11.7  02/19/87                }
  16. {                                                                          }
  17. {       PCBoard Call Analyzer written by Warren Lauzon of Phoenix AZ       }
  18. {                 Phoenix Techline PCBoard   602-936-3058                  }
  19. {                                                                          }
  20. {      (updated for PCBoard 11.8 and PCB ProDOOR, S.H.Smith, 09/02/87)     }
  21. {              (updated for PCBoard 12.1 S.H.Smith, 11/20/87)              }
  22.  
  23.  
  24. const
  25.    version = '14s5';
  26.    reldate = '10-13-88';
  27.    pcbversion = 'For PCBoard v14.0';
  28.  
  29. type
  30.    anystring = string[80];
  31.    FileStr = array[1..64] of char;
  32.  
  33.    ItemPointer = ^ItemList;
  34.    ItemList = record
  35.                  name : string[20];
  36.                  count : longint;
  37.                  next : ItemPointer;
  38.               end;
  39.  
  40.    FilePointer = ^FileRec;
  41.    FileRec = record
  42.                 name : string[16];
  43.                 count : longint;
  44.                 size : longint;
  45.                 higher : FilePointer;
  46.                 lower : FilePointer;
  47.              end;
  48.  
  49.    ProtocolRecord = record
  50.                        Code : char;
  51.                        Name : string[20];
  52.                        Uploads : longint; {count of uploads}
  53.                        UpTime : real; {time spent uploading}
  54.                        UpIdeal : real; {ideal time if 100% efficient}
  55.                        Downloads : longint;
  56.                        DownTime : real;
  57.                        DownIdeal : real;
  58.                     end;
  59.  
  60. const
  61.    ProtocolCount = 27;
  62.    Protocol : array[1..ProtocolCount] of ProtocolRecord = (
  63.       (Code : 'A'; Name : 'ASCII'),
  64.       (Code : 'B'; Name : 'B'),
  65.       (Code : 'C'; Name : 'CRC Xmodem'),
  66.       (Code : 'D'; Name : 'D'),
  67.       (Code : 'E'; Name : 'E'),
  68.       (Code : 'F'; Name : 'Full Flow'),
  69.       (Code : 'G'; Name : 'Ymodem-G (dsz)'),
  70.       (Code : 'H'; Name : 'H'),
  71.       (Code : 'I'; Name : 'I'),
  72.       (Code : 'J'; Name : 'Jmodem'),
  73.       (Code : 'K'; Name : 'Kermit'),
  74.       (Code : 'L'; Name : 'Sysop (Local)'),
  75.       (Code : 'M'; Name : 'MegaLink'),
  76.       (Code : 'N'; Name : 'N'),
  77.       (Code : 'O'; Name : '1K-Xmodem'),
  78.       (Code : 'P'; Name : 'PCP-Zmodem'),
  79.       (Code : 'Q'; Name : 'Q'),
  80.       (Code : 'R'; Name : 'Zmodem Resume'),
  81.       (Code : 'S'; Name : 'SEAlink'),
  82.       (Code : 'T'; Name : 'T'),
  83.       (Code : 'U'; Name : 'U'),
  84.       (Code : 'V'; Name : 'Overdrive SEAlink'),
  85.       (Code : 'W'; Name : 'Window Xmodem'),
  86.       (Code : 'X'; Name : 'Xmodem'),
  87.       (Code : 'Y'; Name : 'Ymodem Batch'),
  88.       (Code : 'Z'; Name : 'Zmodem Batch'),
  89.       (Code : '?'; Name : 'Others')  {must be last}
  90.    );
  91.  
  92.  
  93. (* -------------------------------------------------------- *)
  94. const
  95.    maxdir = 60;
  96.  
  97. var
  98.    search_dir: array[1..maxdir] of string[65];
  99.    search_dirs: integer;
  100.  
  101.  
  102. (* -------------------------------------------------------- *)
  103. var
  104.    first_record : word;
  105.    total_records : word;
  106.    viewmember : longint;   {number of arc member textviews}
  107.    extarc : longint;       {number of arc member extracts}
  108.    rearcs : longint;       {number of re-archive runs}
  109.    arctest : longint;      {number of archives tested}
  110.    arcview : longint;      {number of ARC views}
  111.    B1200 : longint;
  112.    B19200 : longint;       {Baud rate calls}
  113.    B2400 : longint;
  114.    B300 : longint;
  115.    B9600 : longint;
  116.    backdos : longint;      {number of times back from dos}
  117.    batchs : longint;       {number of batch transfers}
  118.    baud : longint;         {current caller's baud rate}
  119.    Blocal : longint;
  120.    blts : longint;         {bulletins read}
  121.    caller : longint;       {number of callers}
  122.    comments : longint;     {number of comments}
  123.    dirscan : longint;      {number of DIR scans}
  124.    DOORs : longint;        {number of DOORs opened}
  125.    DosTimes : longint;     {how many times dropped to DOS}
  126.    down : longint;         {number of downloads}
  127.    d_abort : longint;      {number of download aborts}
  128.    elapsed_time : real;    {how long it takes the program to run}
  129.    Endtime : real;         {End time for program start}
  130.    events : longint;       {event timer activated}
  131.    even_parity : longint;  {7E callers}
  132.    free_down : longint;    {free downloads}
  133.    graphics : longint;     {graphics callers}
  134.    joins : longint;        {number of conference joins}
  135.    kills : longint;        {messages killed}
  136.    lockouts : longint;     {Automatic lockouts done}
  137.    logsize : word;
  138.    mssgs : longint;        {messages left}
  139.    new_guys : longint;     {new users registered}
  140.    non_graphics : longint; {non-graphics callers}
  141.    outfile : anystring;    {output filename}
  142.    PAGE : longint;         {sysop pages}
  143.    pwfail : longint;       {password fails}
  144.    question : longint;     {main questionnaire answered}
  145.    refused : longint;      {refused to register}
  146.    secviol : longint;      {security violations}
  147.    start_time : real;      {0 time for program start}
  148.    stuff : longint;
  149.    sysop_local : longint;  {local sysop sessions}
  150.    sysop_remote : longint; {remote sysop sessions}
  151.    tcan : longint;         {number of trashcan name attempts}
  152.    time_limit : longint;   {daily time limit exceeded}
  153.    TotHours : real;        {Total hours from first to last log entry}
  154.    UniqFiles : longint;    {number of dIfferent files}
  155.    up : longint;           {number of uploads}
  156.    u_abort : longint;      {number of upload aborts}
  157.    min_download : longint; {minimum nummber of downloads to include in report}
  158.    arcmail : longint;      {number of ARCM runs}
  159.    msgcount : longint;     {number of ARCM messges}
  160.    invalids : longint;     {number of invalid uploads}
  161.  
  162.    schat : longint;        {sysop chat initiated}
  163.    nchat:  longint;        {node chat initiated}
  164.       
  165.    UsedMinutes : longint;  {time used, minutes}
  166.    Hours : longint;        {time used, hours}
  167.    mins_dn : longint;      {minutes spent downloading}
  168.    mins_up : longint;      {minutes spent uploading}
  169.    mins_schat: longint;    {minutes spent in sysop-chat mode}
  170.    mins_nchat: longint;    {minutes spent in node-chat mode}
  171.    DosTime : longint;      {time spent in remote DOS}
  172.  
  173.    spare1 : longint;
  174.    spare2 : longint;
  175.    spare3 : longint;
  176.    spare4 : longint;
  177.    spare5 : longint;
  178.    spare6 : longint;
  179.    spare7 : longint;
  180.    spare8 : longint;
  181.    spare9 : longint;
  182.    spare10: longint;
  183.  
  184.  
  185.    Inrec : FileStr;        {64 char line}
  186.    PeriodCovered : anystring; {concats to send to ofd}
  187.    reports : anystring;    {list of reports to produce}
  188.    first_rec : string[64]; {first entry in log}
  189.  
  190.    {table of peak hours, 'Y'=peak, anything else=not}
  191.    PeakTable:  string[24];
  192.  
  193.    Hrs : array[0..23] of longint; {minutes used by hours}
  194.  
  195.    DiskFile : buffered_file;
  196.    FileTree : FilePointer;
  197.    FirstBatch : ItemPointer;
  198.    FirstBullet : ItemPointer;
  199.    FirstConf : ItemPointer;
  200.    FirstDoor : ItemPointer;
  201.    ofd : text;        {file that goes to the bulletin}
  202.    filever: integer;
  203.  
  204. const
  205.    graph_num = 100;
  206.    graph_set : string[3] = '░▓▒';
  207.  
  208. type
  209.    sort_keys = (percent_sort, name_sort, no_sort);
  210.  
  211. var
  212.    graph_min,
  213.    graph_max : longint;
  214.    graph_lim : real;
  215.    graph_line : longint;
  216.    graph_val : array[1..graph_num] of real;
  217.    graph_title : array[1..graph_num] of string[20];
  218.    graph_count : integer;
  219.  
  220.  
  221. (* -------------------------------------------------------- *)
  222. procedure section_title(title : anystring);
  223.    begin
  224.       writeln(ofd);
  225.       writeln(ofd, '' : 35-(length(title) div 2), '-= ', title, ' =-');
  226.       writeln(ofd);
  227.    end;
  228.  
  229.  
  230. procedure empty_section;
  231.    begin
  232.       writeln(ofd, '':34,'**NONE**');
  233.    end;
  234.  
  235.  
  236. procedure start_graph(title : anystring; limit : real);
  237.    begin
  238.       graph_lim := limit;
  239.       graph_max := 0;
  240.       graph_min := 100;
  241.       graph_line := 0;
  242.       graph_count := 0;
  243.       section_title(title);
  244.    end;
  245.  
  246. procedure graph(item : anystring; n : real);
  247.    var
  248.       pct : real;
  249.    begin
  250.       if graph_lim = 0 then
  251.          pct := 0
  252.       else
  253.          pct := abs(n/graph_lim)*100.0;
  254.       if (pct <= 0) or (pct > maxint) then
  255.          exit;
  256.  
  257.     { if pct > 100 then
  258.          pct := 100;   }
  259.  
  260.       if pct > graph_max then
  261.          graph_max := trunc(pct);
  262.       if pct < graph_min then
  263.          graph_min := trunc(pct*0.7);
  264.  
  265.       if graph_count < graph_num then
  266.          inc(graph_count);
  267.  
  268.       graph_val[graph_count] := n;
  269.       graph_title[graph_count] := item;
  270.    end;
  271.  
  272.  
  273. procedure graph_output(item : anystring; n : real);
  274.    var
  275.       pct : real;
  276.       i : integer;
  277.       w : integer;
  278.       lim : longint;
  279.    begin
  280.       if graph_line < length(graph_set) then
  281.          inc(graph_line)
  282.       else
  283.          graph_line := 1;
  284.  
  285.       if graph_lim = 0 then
  286.          pct := 0
  287.       else
  288.          pct := abs(n/graph_lim*100.0);
  289.  
  290.       if pct > 100 then
  291.          pct := 100;
  292.  
  293.       if graph_lim < 0 then
  294.          write(ofd, item:20, ': ', pct:4:1, '% ')
  295.       else
  296.       if int(graph_lim) <> graph_lim then
  297.          write(ofd, item:20, ': ', n:5:1, ' (', pct:4:1, '%) ')
  298.       else
  299.          write(ofd, item:20, ': ', n:4:0, ' (', pct:4:1, '%) ');
  300.  
  301.       if graph_lim < 0 then lim := 50 else lim := 42;
  302.  
  303.       if (pct < graph_min) then
  304.          w := 0
  305.       else
  306.       if (graph_min = graph_max) then
  307.          w := lim
  308.       else
  309.          w := round((pct-graph_min)/(graph_max-graph_min)*lim);
  310.  
  311.       if w > lim then
  312.          w := lim;
  313.  
  314.       write(ofd, '│');
  315.       for i := 1 to w-1 do
  316.          write(ofd, graph_set[graph_line]);
  317.       if w > 0 then
  318.          write(ofd, '█');
  319.  
  320.       writeln(ofd);
  321.    end;
  322.  
  323.  
  324.    procedure sort_graph(onkey: sort_keys);
  325.    var
  326.       ts : string[20];
  327.       tv : real;
  328.       swap : boolean;
  329.       i,j : integer;
  330.  
  331.       function swap_needed: boolean;
  332.       begin
  333.          if onkey = percent_sort then
  334.             tv := graph_val[i]-graph_val[i+1]
  335.          else
  336.             tv := 0;
  337.          if tv = 0 then
  338.             if graph_title[i] > graph_title[i+1] then
  339.                tv := -1;
  340.          swap_needed := (tv < 0);
  341.       end;
  342.       
  343.       procedure swap_entries;
  344.       begin
  345.          swap := true;
  346.          tv := graph_val[i+1];
  347.          graph_val[i+1] := graph_val[i];
  348.          graph_val[i] := tv;
  349.          ts := graph_title[i+1];
  350.          graph_title[i+1] := graph_title[i];
  351.          graph_title[i] := ts;
  352.       end;
  353.  
  354.    begin
  355.  
  356.      j := graph_count;
  357.      repeat
  358.          swap := false;
  359.          dec(j);
  360.          for i := 1 to j do
  361.             if swap_needed then
  362.                swap_entries;
  363.       until swap = false;
  364.    end;
  365.  
  366.  
  367. procedure end_graph(onkey: sort_keys);
  368.    var
  369.       i : integer;
  370.  
  371.    begin
  372.       if onkey <> no_sort then
  373.          sort_graph(onkey);
  374.  
  375.       for i := 1 to graph_count do
  376.          graph_output(graph_title[i], graph_val[i]);
  377.  
  378.       if graph_count = 0 then
  379.          empty_section;
  380.  
  381.       writeln(ofd);
  382.    end;
  383.  
  384.  
  385. (* -------------------------------------------------------- *)
  386.    procedure graph_list(node: ItemPointer;
  387.                         title: string; 
  388.                         n: real; key: sort_keys);
  389.    begin
  390.       start_graph(title,n);
  391.       while node <> nil do
  392.          begin
  393.             graph(node^.name, node^.count);
  394.             node := node^.next;
  395.          end;
  396.       end_graph(key);
  397.    end;
  398.  
  399.  
  400. (* -------------------------------------------------------- *)
  401. procedure walk_tree( var Node : FilePointer;
  402.                      var a : integer);
  403.    {traverse the binary filename tree and output in sorted order}
  404. begin
  405.    if Node = nil then exit;
  406.  
  407.    walk_tree(Node^.lower, a);
  408.  
  409.    if Node^.count >= min_download then
  410.    begin
  411.       case Node^.count-min_download of
  412.          0.. 2: write(ofd, '     ');
  413.          3.. 6: write(ofd, '   * ');
  414.          7..12: write(ofd, '  ** ');
  415.         13..24: write(ofd, ' #** ');
  416.          else   write(ofd, '##** ');
  417.       end;
  418.  
  419.       write(ofd, Node^.name : 12, Node^.count : 5);
  420.  
  421.       if a mod 3 = 0 then
  422.          writeln(ofd)
  423.       else
  424.          write(ofd,'   ');
  425.  
  426.       inc(a);
  427.    end;
  428.  
  429.    walk_tree(Node^.higher, a);
  430. end;
  431.  
  432.  
  433. (* -------------------------------------------------------- *)
  434. procedure output_results;
  435.    var
  436.       UsedHours : real;
  437.       H24 : real;
  438.       DownEffic : real;
  439.       UpEffic : real;
  440.       temp : anystring;
  441.       Days : longint;
  442.       report : integer;
  443.       c: char;
  444.       PeakUsed : real;
  445.       PeakHours : real;
  446.  
  447.       procedure init_report;
  448.       var
  449.          i,j: integer;
  450.       begin
  451.          gotoxy(15, 15);
  452.          HIGHVIDEO;
  453.          textcolor(14);
  454.          gotoxy(1, 2);
  455.          write('Sending output to ', outfile);
  456.          gotoxy(1, 24);
  457.  
  458.          assign(ofd, outfile);
  459.          rewrite(ofd);
  460.  
  461.          UsedHours := int(UsedMinutes)/60.0+int(Hours);
  462.  
  463.          if TotHours < 1 then
  464.             TotHours := 1;
  465.          Days := trunc((TotHours+23.0)/24.0);
  466.          str(days,temp);
  467.  
  468.          {calculate number of hours in peak times}
  469.          i := 0;
  470.          for j := 0 to 23 do
  471.             if PeakTable[j+1] = 'Y' then
  472.                inc(i);
  473.          if i = 0 then
  474.             i := 24;
  475.          PeakHours := TotHours / 24.0 * int(i);
  476.  
  477.          {calculate time used in peak times}
  478.          if i = 24 then
  479.             PeakUsed := UsedHours
  480.          else
  481.          begin
  482.             PeakUsed := 0;
  483.             for j := 0 to 23 do
  484.                if PeakTable[j+1] = 'Y' then
  485.                   PeakUsed := PeakUsed + int(hrs[j])/60.0;
  486.          end;
  487.  
  488.          writeln(ofd);
  489.          writeln(ofd, '                  Calls ', version, ' - Call Analyzer ',pcbversion);
  490.          writeln(ofd,'            ', PeriodCovered);
  491.       end;
  492.  
  493.       procedure system_statistics;
  494.       begin
  495.          section_title('System Statistics for '+temp+' days');
  496.  
  497.          write  (ofd, '  Archive REPAK Runs .... ', rearcs:6);
  498.          writeln(ofd, '  Comments Left ......... ':33, comments:6);
  499.  
  500.          write  (ofd, '  Archive Texts Viewed .. ', viewmember:6);
  501.          writeln(ofd, '  Messages Left ......... ':33, mssgs:6);
  502.  
  503.          write  (ofd, '  Archive Extracts ...... ', extarc:6);
  504.          writeln(ofd, '  Archive Mail Runs ..... ':33, arcmail:6);
  505.  
  506.          write  (ofd, '  Archives Tested ....... ', arctest:6);
  507.          writeln(ofd, '  Archive Mail Messages . ':33, msgcount:6);
  508.  
  509.          write  (ofd, '  Archives Viewed ....... ', arcview:6);
  510.          writeln(ofd, '  Number of Callers ..... ':33, caller:6);
  511.  
  512.          write  (ofd, '  Directory Scans ....... ', dirscan:6);
  513.          writeln(ofd, '  New Users Registered .. ':33, new_guys:6);
  514.  
  515.          write  (ofd, '  Doors Opened .......... ', DOORs:6);
  516.          writeln(ofd, '  Questionnaire Answered. ':33, question:6);
  517.  
  518.          write  (ofd, '  Downloads Aborted ..... ', d_abort:6);
  519.          writeln(ofd, '  Average Call Length ... ':33, (UsedHours*60)/caller:6:1);
  520.  
  521.          write  (ofd, '  Downloads Completed ... ', down:6);
  522.          writeln(ofd, '  Average Idle Time ..... ':33, (TotHours-UsedHours)*60/caller:6:1);
  523.  
  524.          write  (ofd, '  Different Files Dnld .. ', UniqFiles:6);
  525.          writeln(ofd, '  Calls per day (avg) ... ':33, caller/Days:6:1);
  526.  
  527.          write  (ofd, '  Free downloads ........ ', free_down:6);
  528.          writeln(ofd, '  Time Used, Hours ...... ':33, UsedHours:6:1);
  529.  
  530.          write  (ofd, '  Uploads Aborted ....... ', u_abort:6);
  531.          writeln(ofd, '  Total Operation Hours . ':33, TotHours:6:1);
  532.  
  533.          write  (ofd, '  Uploads Completed ..... ', up:6);
  534.          writeln(ofd, '  Total Utilization % ... ':33, (UsedHours/TotHours)*100:6:1);
  535.  
  536.          write  (ofd, '  Bad archives deleted .. ', invalids:6);
  537.          writeln(ofd, '  Peak Utilization % .... ':33, (PeakUsed/PeakHours)*100:6:1);
  538.          writeln(ofd);
  539.       end;
  540.  
  541.       procedure security_statistics;
  542.       begin
  543.          section_title('Security Statistics');
  544.  
  545.          write  (ofd, '':32);
  546.          writeln(ofd, '  Node Chats Initiated... ':33, nchat:6);
  547.  
  548.          write  (ofd, '  Automatic Lockouts .... ', lockouts:6);
  549.          writeln(ofd, '  Sysop Chats Initiated.. ':33, schat:6);
  550.  
  551.          write  (ofd, '  Password Failures ..... ', pwfail:6);
  552.          writeln(ofd, '  Sysop Paged ........... ':33, PAGE:6);
  553.  
  554.          write  (ofd, '  Refused to Register ... ', refused:6);
  555.          writeln(ofd, '  Sysop Sessions ........ ':33, sysop_local+sysop_remote:6);
  556.  
  557.          write  (ofd, '  Remote DOS Time (min) . ', DosTime:6);
  558.          writeln(ofd, '  Time Limit Expired .... ':33, time_limit:6);
  559.  
  560.          write  (ofd, '  Remote Drops to DOS ... ', DosTimes:6);
  561.          writeln(ofd, '  Trashcan Names ........ ':33, tcan:6);
  562.  
  563.          write  (ofd, '  Scheduled Events ...... ', events:6);
  564.          writeln(ofd, '  Security Violations ... ':33, secviol:6);
  565.          writeln(ofd);
  566.       end;
  567.  
  568.       procedure graphic_modes;
  569.       var
  570.          k: longint;
  571.       begin
  572.          k := (graphics+non_graphics+even_parity);
  573.          start_graph('Graphics Modes', k);
  574.          graph('Color Graphics', graphics);
  575.          graph('Non Graphics', non_graphics);
  576.          graph('7 Bit Even-Parity', even_parity);
  577.          end_graph(percent_sort);
  578.       end;
  579.  
  580.       procedure baud_rates;
  581.       begin
  582.          start_graph('Baud Rates', B19200+B9600+B2400+B1200+B300);
  583.          graph('19200 Baud', B19200);
  584.          graph('9600 Baud', B9600);
  585.          graph('2400 Baud', B2400);
  586.          graph('1200 Baud', B1200);
  587.          graph('300 Baud', B300);
  588.          end_graph(no_sort);
  589.       end;
  590.  
  591.       procedure hourly_usage;
  592.       var
  593.          hits: longint;
  594.          slot: integer;
  595.          a:    integer;
  596.          k:    integer;
  597.       begin
  598.          section_title('Average Percent of Hourly Usage');
  599.          if TotHours > 24 then H24 := (TotHours/24)*(60/100)
  600.          else H24 := 0.60;
  601.  
  602.          hits := 0;
  603.          for k := 20 downto 1 do 
  604.          {if hits < 24 then}
  605.          begin
  606.             write(ofd, k*5 : 3, '% │ ');
  607.             hits := 0;
  608.  
  609.             for a := 0 to 23 do 
  610.             begin
  611.                c := graph_set[(a mod 3)+1];
  612.                slot := trunc((hrs[a] / H24) / 5);
  613.                if slot > 20 then slot := 20;
  614.                if slot = k then
  615.                   write(ofd, '██ ')
  616.                else
  617.                if slot > k then
  618.                begin
  619.                   write(ofd, c,c,' ');
  620.                   inc(hits);
  621.                end
  622.                else 
  623.                   write(ofd, ' · ');
  624.             end;
  625.  
  626.             writeln(ofd);
  627.          end;
  628.  
  629.          write(ofd, '       00');
  630.          for a := 1 to 23 do
  631.             write(ofd,a:3);
  632.          writeln(ofd);
  633.  
  634.          write(ofd, 'Peak: ');
  635.          for a := 0 to 23 do
  636.             if PeakTable[a+1] = 'Y' then
  637.                write(ofd,' **')
  638.             else
  639.                write(ofd,'   ');
  640.          writeln(ofd);
  641.          writeln(ofd);
  642.       end;
  643.  
  644.       procedure conferences_joined;
  645.       begin
  646.          graph_list(FirstConf,'Conferences Joined', joins, percent_sort);
  647.       end;
  648.  
  649.       procedure bulletins_read;
  650.       begin
  651.          graph_list(FirstBullet,'Bulletins Read', blts, percent_sort);
  652.       end;
  653.  
  654.       procedure doors_opened;
  655.       begin
  656.          graph_list(FirstDoor,'Doors Opened', DOORs, percent_sort);
  657.       end;
  658.  
  659.       procedure time_distribution;
  660.       var
  661.          u: longint;
  662.       begin
  663. (***
  664.          start_graph('Time Usage by Activity (Hours)', TotHours);
  665.          graph('Uploading',mins_up/60.0);
  666.          graph('Downloading',mins_dn/60.0);
  667.          graph('Remote DOS Time', DosTime/60.0);
  668.          graph('Sysop Chat Time', mins_schat/60.0);
  669.          graph('Node Chat Time', mins_nchat/60.0);
  670.          graph('Waiting For Calls',TotHours-UsedHours);
  671.          u := mins_up + mins_dn + mins_schat + mins_nchat + DosTime;
  672.          graph('All Other Activities',UsedHours - u/60.0);
  673.          end_graph(percent_sort);
  674. ***)
  675.       end;
  676.  
  677.       procedure download_protocols;
  678.       var
  679.          k: integer;
  680.       begin
  681.          start_graph('Protocol Usage (Downloading)', down);
  682.          for k := 1 to ProtocolCount do
  683.             with Protocol[k] do
  684.                if (Downloads <> 0) then
  685.                   graph(Name, Downloads);
  686.          end_graph(percent_sort);
  687.       end;
  688.  
  689.       procedure download_efficiency;
  690.       var
  691.          k: integer;
  692.       begin
  693.          start_graph('Average Protocol Efficiency (Downloading)', -100);
  694.          for k := 1 to ProtocolCount do
  695.             with Protocol[k] do
  696.                if (Downloads <> 0) and (DownTime <> 0) then
  697.                   begin
  698.                      DownEffic := 100.0*DownIdeal/DownTime;
  699.                      graph(Name, DownEffic);
  700.                   end;
  701.          end_graph(percent_sort);
  702.       end;
  703.  
  704.       procedure upload_protocols;
  705.       var
  706.          k: integer;
  707.       begin
  708.          start_graph('Protocol Usage (Uploading)', up);
  709.          for k := 1 to ProtocolCount do
  710.             with Protocol[k] do
  711.                if (Uploads <> 0) then
  712.                   graph(Name, Uploads);
  713.          end_graph(percent_sort);
  714.       end;
  715.  
  716.       procedure upload_efficiency;
  717.       var
  718.          k: integer;
  719.       begin
  720.          start_graph('Average Protocol Efficiency (Uploading)', -100);
  721.          for k := 1 to ProtocolCount do
  722.             with Protocol[k] do
  723.                if (Uploads <> 0) and (UpTime <> 0) then
  724.                   begin
  725.                      UpEffic := 100.0*UpIdeal/UpTime;
  726.                      graph(Name, UpEffic);
  727.                   end;
  728.          end_graph(percent_sort);
  729.       end;
  730.  
  731.       procedure batch_sizes;
  732.       begin
  733.          graph_list(FirstBatch,'Batch Transfer Sizes', batchs, name_sort);
  734.       end;
  735.  
  736.       procedure files_downloaded;
  737.       var
  738.          a: integer;
  739.       begin
  740.          section_title('Files Downloaded');
  741.          if down < 1 then
  742.             empty_section
  743.          else
  744.             begin
  745.                a := 1;
  746.                walk_tree(FileTree, a);
  747.             end;
  748.          writeln(ofd);
  749.       end;
  750.  
  751. (* -------------------------------------------------------- *)
  752.    begin
  753.       init_report;
  754.  
  755.       for report := 1 to length(reports) do
  756.          case upcase(reports[report]) of
  757.            'A': system_statistics;
  758.            'B': graphic_modes;
  759.            'C': baud_rates;
  760.            'D': hourly_usage;
  761.            'E': conferences_joined;
  762.            'F': bulletins_read;
  763.            'G': doors_opened;
  764.            'H': download_protocols;
  765.            'I': download_efficiency;
  766.            'J': upload_protocols;
  767.            'K': upload_efficiency;
  768.            'L': batch_sizes;
  769.            'M': files_downloaded;
  770.            'N': security_statistics;
  771.            'O': time_distribution;
  772.            'Z': writeln(ofd);
  773.          end;
  774.  
  775.       close(ofd);
  776.    end;
  777.  
  778.  
  779.  
  780. (* -------------------------------------------------------- *)
  781. procedure getrec;
  782.    var
  783.       c:    char;
  784.    begin
  785.       bread(DiskFile, Inrec);
  786.  
  787.       if keypressed then
  788.       begin
  789.          c := readkey;
  790.          if c = #27 then
  791.          begin
  792.             gotoxy(1, 24);
  793.             writeln('** ESC pressed - Aborted **');
  794.             delay(2000);
  795.             halt;
  796.          end;
  797.       end;
  798.  
  799.    end;
  800.  
  801.  
  802. (* -------------------------------------------------------- *)
  803. function get_file_size(name: string): longint;
  804.    {get the size of a file; somewhere in download paths}
  805. var
  806.    path:    string;
  807.    i:       integer;
  808.    DirInfo: SearchRec;
  809.  
  810. begin
  811. (***
  812.    name[9] := '.';
  813.    repeat
  814.       i := pos(' ',name);
  815.       if i >0 then
  816.          delete(name,i,1);
  817.    until i = 0;
  818.  
  819.    for i := 1 to search_dirs do
  820.    begin
  821.       path := search_dir[i] + '\' + name;
  822.  
  823.       FindFirst(path,$21,DirInfo);
  824.       if (DosError = 0) then
  825.       begin
  826.          gotoxy(23,3);
  827.          write('File: ',name:12,'   Size:',dirinfo.size:7);
  828.          get_file_size := DirInfo.size;
  829.          exit;
  830.       end;
  831.    end;
  832.  
  833.    gotoxy(23,3);
  834.    write('File: ',name:12,'  Not found!  ');
  835. ***)
  836.    get_file_size := 60000;
  837. end;
  838.  
  839.  
  840. (* -------------------------------------------------------- *)
  841. procedure add_item(var FirstItem : ItemPointer;
  842.                    ItemName : anystring;
  843.                    Number : integer);
  844. var
  845.    NewItem : ItemPointer;
  846.  
  847. begin
  848.    NewItem := FirstItem;
  849.    while NewItem <> nil do
  850.       if NewItem^.name = ItemName then
  851.          begin
  852.             NewItem^.count := NewItem^.count + Number;
  853.             exit;
  854.          end
  855.       else
  856.          NewItem := NewItem^.next;
  857.  
  858.    new(NewItem);          { get a new record}
  859.    NewItem^.next := FirstItem;
  860.    FirstItem := NewItem;
  861.    NewItem^.name := ItemName;
  862.    NewItem^.count := Number;
  863. end;
  864.  
  865.  
  866. (* -------------------------------------------------------- *)
  867. procedure store_name(var Node : FilePointer;
  868.                      var Name : anystring;
  869.                      var Size : longint);
  870.       {stores the name in the sorted name tree; recursive}
  871.  
  872.    begin
  873.  
  874.       (* insert new nodes *)
  875.       if Node = nil then
  876.       begin
  877.          new(Node);
  878.          Node^.count := 1;
  879.          Node^.name := Name;
  880.          Node^.size := get_file_size(Name);
  881.          Size := Node^.size;
  882.          Node^.higher := nil;
  883.          Node^.lower := nil;
  884.          inc(UniqFiles);
  885.       end
  886.       else
  887.  
  888.       (* count existting nodes *)
  889.       if Node^.name = Name then
  890.       begin
  891.          inc(Node^.count);
  892.          Size := Node^.size;
  893.       end
  894.       else
  895.  
  896.       (* else traverse the tree looking for the right node *)
  897.       if Name > Node^.name then
  898.          store_name(Node^.higher,Name,Size)
  899.       else
  900.          store_name(Node^.lower,Name,Size);
  901.    end;
  902.  
  903.  
  904. (* -------------------------------------------------------- *)
  905. type
  906.    str12 = string[12];
  907.    str80 = string[80];
  908.  
  909. {  This Function returns a name expanded to line up both the name and ext    }
  910. {  for example:  abc.com      =  abc      com                                }
  911. {                datafile.1   =  datafile   1                                }
  912.  
  913. function ExpandName(name : str12) : str12;
  914.  
  915.    var
  916.       Counter, DotPos : integer;
  917.  
  918.    begin
  919.       DotPos := pos('.', name); {where's the dot at?}
  920.       if DotPos = 0 then begin
  921.          repeat
  922.             name := name+' '; {If no ext, pad with spaces}
  923.          until length(name) = 12;
  924.       end else begin
  925.          delete(name, DotPos, 1);
  926.          repeat
  927.             insert(' ', name, DotPos);
  928.          until length(name) = 12;
  929.       end;
  930.       ExpandName := name;
  931.    end;
  932.  
  933.  
  934. (* -------------------------------------------------------- *)
  935. procedure print(col, row : integer;
  936.                 str : str80;
  937.                 Attrib : integer);
  938.    begin
  939.       gotoxy(col, row);
  940.       textcolor(Attrib);
  941.       write(str);
  942.    end;
  943.  
  944.  
  945. (* -------------------------------------------------------- *)
  946. function Time : real;
  947.  
  948.    var
  949.       Reg : Registers;
  950.  
  951.    begin Reg.AX := $2C00;
  952.       intr($21, Reg);
  953.       Time := (Reg.CX shr 8)*3600 {Hours}
  954.       +(Reg.CX and $00FF)*60 {Minutes}
  955.       +(Reg.DX shr 8)      { * 1 }
  956.                            {Seconds    }
  957.       +(Reg.DX and $00FF)/100; {Hundredths }
  958.    end;
  959.  
  960.  
  961.  
  962. (* -------------------------------------------------------- *)
  963. procedure incaller;
  964.    var
  965.       Str30 : string[30];
  966.       posit : integer;
  967.       str20 : string[20];
  968.  
  969.    begin
  970.       if pos('New', Inrec) > 0 then
  971.          exit;
  972.       if pos('Off', Inrec) > 0 then
  973.          exit;
  974.  
  975.       if pos(' SYSOP (', Inrec) > 0 then
  976.          begin
  977.             if pos(' (Local) (', Inrec) > 0 then inc(sysop_local)
  978.             else inc(sysop_remote);
  979.          end;
  980.  
  981.       if pos(' (Local) (', Inrec) <> 0 then baud := 0
  982.       else if pos(' (19200) (', Inrec) <> 0 then baud := 19200
  983.       else if pos(' (9600) (', Inrec) <> 0 then baud := 9600
  984.       else if pos(' (2400) (', Inrec) <> 0 then baud := 2400
  985.       else if pos(' (1200) (', Inrec) <> 0 then baud := 1200
  986.       else if pos(' (300) (', Inrec) <> 0 then baud := 300;
  987.  
  988.       case baud of
  989.          19200 : begin
  990.                     inc(B19200);
  991.                     baud := 13000;  {highest effective speed}
  992.                  end;
  993.  
  994.          9600 :  inc(B9600);
  995.          2400 :  inc(B2400);
  996.          1200 :  inc(B1200);
  997.          300 :   inc(B300);
  998.       else inc(Blocal);
  999.       end;
  1000.  
  1001.       if pos('(G', Inrec) > 0 then inc(graphics)
  1002.       else if pos('(N', Inrec) > 0 then inc(non_graphics)
  1003.       else if pos('(7', Inrec) > 0 then inc(even_parity);
  1004.  
  1005.       caller := Blocal+B300+B1200+B2400+B9600+B19200;
  1006.  
  1007.       if pos('Trashcan', Inrec) > 0 then inc(tcan);
  1008.    end;
  1009.  
  1010.  
  1011. (* -------------------------------------------------------- *)
  1012. procedure indownload;      {upload/downloaded file stuff}
  1013.    var
  1014.       prot : char;
  1015.       posit : integer;
  1016.       k : integer;
  1017.       CPS : real;
  1018.       FileName : string[12];
  1019.       tmp: string;
  1020.       size : longint;
  1021.       ideal : real;
  1022.       Time : real;
  1023.  
  1024.    begin
  1025.       if pos(' Aborted using ', Inrec) > 12 then
  1026.       begin
  1027.          if inrec[8] = 'D' then
  1028.             inc(d_abort) {Aborted dl's}
  1029.          else
  1030.             inc(u_abort);
  1031.          exit;
  1032.       end;
  1033.  
  1034.       if inrec[8] = 'D' then
  1035.          inc(down)
  1036.       else
  1037.          inc(up);
  1038.  
  1039.       {determine file name}
  1040.       posit := pos(' Completed using ', Inrec); {find End of name}
  1041.       if posit=0 then exit;
  1042.  
  1043.       FileName := copy(Inrec, 11, (posit-11));
  1044.       FileName := ExpandName(FileName);
  1045.       if FileName[1] = ' ' then exit;
  1046.  
  1047.       {store name, return file size}
  1048.       store_name(FileTree,FileName,size);
  1049.  
  1050.       {determine transfer time}
  1051.       if baud <> 0 then
  1052.          ideal := size/baud*10.0
  1053.       else
  1054.          ideal := 111;
  1055.  
  1056.       {determine actual transfer time}
  1057.       posit := pos('CPS=', Inrec);
  1058.       if posit = 0 then
  1059.          CPS := baud/11.0
  1060.       else
  1061.       begin
  1062.          tmp := copy(inrec,posit+4,6);
  1063.          posit := pos(' ',tmp);
  1064.          tmp := copy(tmp,1,posit-1);
  1065.          CPS := 0;
  1066.          val(tmp,cps,posit);
  1067.       end;
  1068.  
  1069.       if (CPS < 20) or (CPS > (baud/5.0)) then
  1070.       begin
  1071.          Time := 0;     {don't consider aborted or invalid transfers}
  1072.          ideal := 0;
  1073.       end
  1074.       else
  1075.          Time := size/CPS;
  1076.  
  1077.       if inrec[8] = 'D' then
  1078.       begin
  1079.          inc(down);
  1080.          mins_dn := mins_dn + round(Time/60.0);
  1081.       end
  1082.       else
  1083.       begin
  1084.          inc(up);
  1085.          mins_up := mins_up + round(Time/60.0);
  1086.       end;
  1087.  
  1088.       {determine protocol and find table entry}
  1089.       posit := pos('using ', Inrec);
  1090.       prot := Inrec[posit+6];
  1091.  
  1092.       for k := 1 to ProtocolCount do
  1093.       with Protocol[k] do
  1094.  
  1095.          if (Code = prot) or (Code = '?') then
  1096.          begin
  1097.             if Code = '?' then
  1098.             begin
  1099.                gotoxy(1,3);
  1100.                writeln('Unknown protocol: ',Inrec);
  1101.             end;
  1102.  
  1103.             if Inrec[8] = 'D' then
  1104.             begin
  1105.                inc(Downloads);
  1106.                DownTime := DownTime+Time;
  1107.                DownIdeal := DownIdeal+ideal;
  1108.             end
  1109.             else
  1110.             begin
  1111.                inc(Uploads);
  1112.                UpTime := UpTime+Time;
  1113.                UpIdeal := UpIdeal+ideal;
  1114.             end;
  1115.  
  1116.             exit;
  1117.          end;
  1118.    end;
  1119.  
  1120.  
  1121. (* -------------------------------------------------------- *)
  1122. procedure confjoin;        {conferences joined}
  1123.  
  1124.    var
  1125.       posit : integer;
  1126.       ConfName : anystring;
  1127.  
  1128.    begin
  1129.       posit := pos(' Conference', Inrec);
  1130.       if posit < 8 then
  1131.          exit;
  1132.  
  1133.       ConfName := copy(Inrec, 7, 10);
  1134.       posit := pos(' ',ConfName);
  1135.       if posit > 0 then
  1136.          ConfName[0] := chr(posit-1);
  1137.  
  1138.       case ConfName[1] of
  1139.          '0'..'9', 'a'..'z', 'A'..'Z':
  1140.          begin
  1141.             inc(joins);
  1142.             add_item(FirstConf, ConfName, 1);
  1143.          end;
  1144.       end;
  1145.    end;
  1146.  
  1147.  
  1148. (* -------------------------------------------------------- *)
  1149. procedure batch;        {batch transfer}
  1150.  
  1151.    var
  1152.       posit : integer;
  1153.       num : integer;
  1154.       temp : anystring;
  1155.       BatchName : anystring;
  1156.  
  1157.    begin
  1158.       posit := pos(' files', Inrec);
  1159.       temp := copy(Inrec,7,posit-7);
  1160.       num := 0;
  1161.       val(temp,num,posit);
  1162.       if num < 1 then
  1163.          exit;
  1164.       if Inrec[posit+7] = '0' then
  1165.          exit;
  1166.  
  1167.       str(num:2,temp);
  1168.       if num = 1 then
  1169.          BatchName := '  Single Files'
  1170.       else
  1171.          BatchName := temp + ' Files';
  1172.  
  1173.       batchs := batchs + num;
  1174.       add_item(FirstBatch, BatchName, num);
  1175.    end;
  1176.  
  1177.  
  1178. (* -------------------------------------------------------- *)
  1179. procedure arcmsgs;        {archived message count}
  1180.    var
  1181.       posit : integer;
  1182.       num : integer;
  1183.    
  1184.    begin
  1185.       posit := pos(' messa', Inrec);
  1186.       num := 0;
  1187.       val(copy(Inrec,7,posit-7),num,posit);
  1188.       if num < 1 then
  1189.          exit;
  1190.       msgcount := msgcount + num;
  1191.    end;
  1192.  
  1193.  
  1194. (* -------------------------------------------------------- *)
  1195. type
  1196.    Days = integer;
  1197. var
  1198.    numdays : integer;
  1199.  
  1200. function finday(Days : integer) : integer;
  1201.  
  1202.    begin
  1203.       case Days of
  1204.          12 : numdays := 334;
  1205.          11 : numdays := 304;
  1206.          10 : numdays := 273;
  1207.          9 : numdays := 243;
  1208.          8 : numdays := 212;
  1209.          7 : numdays := 181;
  1210.          6 : numdays := 151;
  1211.          5 : numdays := 120;
  1212.          4 : numdays := 90;
  1213.          3 : numdays := 59;
  1214.          2 : numdays := 31;
  1215.          1 : numdays := 0;
  1216.       end;                 {case}
  1217.       finday := numdays;
  1218.    end;
  1219.  
  1220.  
  1221. (* -------------------------------------------------------- *)
  1222. procedure openfiles;
  1223.  
  1224.    var
  1225.       end_hours: real;
  1226.       beg_hours: real;
  1227.       mostr, daystr : integer;
  1228.       YrStr, Fract : real;
  1229.       Num_Days : integer;
  1230.       TX : string[62];
  1231.       first_entry : string[19]; {first entry in log}
  1232.       last_entry : string[19]; {last entry in log}
  1233.       a: integer;
  1234.       inName : string[65];
  1235.  
  1236.    begin
  1237.       if paramcount = 0 then 
  1238.          InName :=  'CALLERS'
  1239.       else 
  1240.          InName := paramstr(1);
  1241.  
  1242.       bopen(DiskFile,InName,200,sizeof(InRec));
  1243.       if berr then
  1244.       begin
  1245.          writeln('Cant open caller file: ',InName);
  1246.          halt(1);
  1247.       end;
  1248.  
  1249.       bseekeof(DiskFile);
  1250.       total_records := btell(DiskFile);
  1251.       if total_records < 4 then
  1252.       begin
  1253.          gotoxy(1,24);
  1254.          writeln('Empty caller log - No action taken');
  1255.          halt(99);
  1256.       end;
  1257.  
  1258.       bseek(DiskFile, total_records-1);
  1259.       getrec;
  1260.  
  1261.       if inrec[3] <> '-' then             {check for bad EOF}
  1262.       begin
  1263.          repeat
  1264.             dec(total_records);
  1265.             bseek(DiskFile, total_records-1);
  1266.             getrec;
  1267.          until (inrec[3] = '-') or (total_records < 2);
  1268.       end;
  1269.  
  1270.       {decode the last log entry}
  1271.       dec(total_records);
  1272.       bseek(DiskFile, total_records);
  1273.       getrec;
  1274.  
  1275.       last_entry := copy(Inrec, 11, 5)+' '+copy(Inrec, 1, 8);
  1276.       TX := concat('Last log entry:  '+Inrec);
  1277.       print(3, 23, TX, 10);
  1278.  
  1279.       val(copy(last_entry, 7, 2), mostr, a);     {get month}
  1280.       val(copy(last_entry, 10, 2), daystr, a);   {get day}
  1281.       val(last_entry[14], YrStr, a);             {last digit of year}
  1282.       val(copy(last_entry, 1, 2), end_hours, a); {hour digit of logon}
  1283.       if end_hours > 23 then
  1284.          end_hours := end_hours - 24;
  1285.       val(copy(last_entry, 4, 2), Fract, a);
  1286.       Fract := Fract/60;
  1287.       Num_Days := finday(mostr);
  1288.       end_hours := end_hours + (YrStr*24*365) + Fract + (Num_Days+daystr)*24;
  1289.  
  1290.  
  1291.       {decode the beginning of the logfile}
  1292.       first_record := 0;
  1293.       repeat
  1294.          inc(first_record);
  1295.          bseek(DiskFile, first_record);
  1296.          getrec;
  1297.       until (Inrec[3] = '-') or (first_record >= total_records);
  1298.  
  1299.       if first_rec = '' then
  1300.          first_rec := Inrec;
  1301.       first_entry := copy(first_rec, 11, 5)+' '+copy(first_rec, 1, 8);
  1302.       TX := 'First log entry: '+first_rec;
  1303.       print(3, 22, TX, 10);
  1304.  
  1305.       val(copy(first_entry, 7, 2), mostr, a);
  1306.       val(copy(first_entry, 10, 2), daystr, a);
  1307.       val(first_entry[14], YrStr, a);
  1308.       val(copy(first_entry, 1, 2), beg_hours, a);
  1309.       if beg_hours > 23 then
  1310.          beg_hours := beg_hours - 24;
  1311.       val(copy(first_entry, 4, 2), Fract, a);
  1312.       Fract := Fract/60;
  1313.       Num_Days := finday(mostr);
  1314.       beg_hours := beg_hours + (YrStr*24*365) + Fract + (Num_Days+daystr)*24;
  1315.  
  1316.  
  1317.       {determine the period involved}
  1318.       PeriodCovered := 'Period covered:  From '+first_entry+' to '+last_entry;
  1319.       print(3, 21, PeriodCovered, 13);
  1320.  
  1321.       TotHours := end_hours-beg_hours;
  1322.       str(TotHours : 5 : 1, TX);
  1323.       TX := concat('Total Hours of Operation: ', TX);
  1324.       print(3, 19, TX, 15);
  1325.  
  1326.  
  1327.       logsize := total_records;
  1328.       str(logsize : 5, TX);
  1329.       TX := concat('Total Records in the Callers file: ', TX);
  1330.       print(3, 20, TX, yellow);
  1331.  
  1332.       if total_records < 4 then
  1333.       begin
  1334.          gotoxy(1,24);
  1335.          writeln('Empty caller log - No action taken');
  1336.          halt(99);
  1337.       end;
  1338.  
  1339.       dec(total_records,2);
  1340.       incaller;
  1341.    end;
  1342.  
  1343.  
  1344.  
  1345. (* -------------------------------------------------------- *)
  1346. procedure bulletins;
  1347.  
  1348.    var
  1349.       posit : integer;
  1350.       BltNumber:  anystring;
  1351.       BltName:    anystring;
  1352.  
  1353.    begin
  1354.       BltName := copy(Inrec, 22, 10);
  1355.       posit := pos(' ', BltName);
  1356.       if posit > 0 then
  1357.          BltName[0] := chr(posit-1);
  1358.       if length(BltName) = 0 then
  1359.          exit;
  1360.  
  1361.       posit := pos('#', Inrec);
  1362.       if posit = 0 then
  1363.          exit;
  1364.       BltNumber := copy(Inrec,posit+2,4);
  1365.       posit := pos(' ', BltNumber);
  1366.       if posit > 0 then
  1367.          BltNumber[0] := chr(posit-1);
  1368.       while length(BltNumber) < 3 do
  1369.          BltNumber := ' ' + BltNumber;
  1370.  
  1371.       BltName := BltName + ' #' + BltNumber;
  1372.       inc(blts);
  1373.       add_item(FirstBullet, BltName, 1);
  1374.    end;                    {bulletins}
  1375.  
  1376.  
  1377. (* -------------------------------------------------------- *)
  1378. procedure pdoors;
  1379.  
  1380.    var
  1381.       posit : integer;
  1382.       DoorName : string[40];
  1383.  
  1384.    begin
  1385.       if pos(' at ', Inrec) = 0 then exit;
  1386.  
  1387.       posit := pos('(', Inrec);
  1388.       DoorName := copy(Inrec, posit+1, pos(')', Inrec)-posit-1);
  1389.  
  1390.       posit := 1;
  1391.       repeat
  1392.          if DoorName[posit] = '\' then
  1393.             begin
  1394.                DoorName := copy(DoorName, posit+1, 99);
  1395.                posit := 1;
  1396.             end
  1397.          else
  1398.             posit := posit+1;
  1399.       until posit = length(DoorName);
  1400.  
  1401.       inc(DOORs);
  1402.       add_item(FirstDoor, DoorName, 1);
  1403.    end;
  1404.  
  1405.  
  1406. (* -------------------------------------------------------- *)
  1407. procedure DOSdrop;
  1408.  
  1409.    var
  1410.       DT1, DT2 : integer;
  1411.       a: integer;
  1412.  
  1413.    begin
  1414.       val(copy(Inrec, 34, 2), DT1, a); {exit to DOS time}
  1415.       getrec;
  1416.  
  1417.       val(copy(Inrec, 27, 2), DT2, a); {back from DOS time}
  1418.       if a = 0 then 
  1419.       begin
  1420.          DT1 := (DT2-DT1);
  1421.          if DT1 < 0 then DT1 := DT1+60; {adjust for hour rollover}
  1422.          DosTime := DosTime+DT1;
  1423.       end;
  1424.       inc(DosTimes);
  1425.    end;
  1426.  
  1427.  
  1428. (* -------------------------------------------------------- *)
  1429. procedure sysop_chat;
  1430.  
  1431.    var
  1432.       DT1, DT2 : integer;
  1433.       a: integer;
  1434.       node: boolean;
  1435.  
  1436.    begin
  1437.       node := (inrec[7] = 'N');
  1438.  
  1439.       val(copy(Inrec, 34, 2), DT1, a); {chat started time time}
  1440.       getrec;
  1441.  
  1442.       val(copy(Inrec, 27, 2), DT2, a); {chat ended time}
  1443.       if a = 0 then 
  1444.       begin
  1445.          DT1 := (DT2-DT1);
  1446.          if DT1 < 0 then DT1 := DT1+60; {adjust for hour rollover}
  1447.          if node then
  1448.             mins_nchat := mins_nchat + DT1
  1449.          else
  1450.             mins_schat := mins_schat + DT1;
  1451.       end;
  1452.  
  1453.       if node then
  1454.          inc(nchat)
  1455.       else
  1456.          inc(schat);
  1457.    end;
  1458.  
  1459.  
  1460. (* -------------------------------------------------------- *)
  1461. procedure catchall;
  1462.    begin
  1463.       if pos(' CHAT ', Inrec) > 0 then sysop_chat
  1464.       else if pos('Access Denied', Inrec) > 0 then inc(tcan)
  1465.       else if pos('Comment ', Inrec) > 0 then inc(comments)
  1466.       else if pos(' DOOR ', Inrec) > 0 then pdoors
  1467.       else if pos('Left:', Inrec) > 0 then inc(mssgs)
  1468.       else if pos('not registered', Inrec) > 0 then inc(secviol)
  1469.       else if pos('ock-', Inrec) > 0 then inc(lockouts)
  1470.       else if pos('oined', Inrec) > 0 then confjoin
  1471.       else if pos('Paged', Inrec) > 0 then inc(PAGE)
  1472.       else if pos('Questionnaire ', Inrec) > 0 then inc(question)
  1473.       else if pos('Refused', Inrec) > 0 then inc(refused)
  1474.       else if pos('Scheduled', Inrec) > 0 then inc(events)
  1475.       else if pos('Time Limit', Inrec) > 0 then inc(time_limit)
  1476.       else if pos('Violation', Inrec) > 0 then inc(secviol)
  1477.    end;
  1478.  
  1479.  
  1480. (* -------------------------------------------------------- *)
  1481. procedure scanfile;
  1482.  
  1483.    var
  1484.       tx1 : string[20];
  1485.       a, y, p : integer;
  1486.       minutoff,
  1487.       houroff,
  1488.       timeused : integer;
  1489.       lastx : word;
  1490.  
  1491.    begin
  1492.       lastx := total_records;
  1493.       total_records := first_record;
  1494.  
  1495.       while (total_records <= lastx) do
  1496.       begin
  1497.          if total_records mod 30 = 1 then
  1498.          begin
  1499.             str((int(total_records)/int(logsize)*100.0) : 5 : 1, tx1);
  1500.             tx1 := 'Working.... '+tx1+' %';
  1501.             print(3, 17, tx1, 12);
  1502.          end;
  1503.  
  1504.          inc(total_records);
  1505.          bseek(DiskFile, total_records);
  1506.          getrec;
  1507.  
  1508.          if pos(') (', Inrec) <> 0 then
  1509.             incaller
  1510.          else
  1511.  
  1512.             if (pos('Minutes Used', Inrec) > 0) then
  1513.             begin
  1514.                p := pos(':', Inrec)+2;
  1515.                y := p;
  1516.                while (Inrec[y] >= '0') and (Inrec[y] <= '9') do
  1517.                   inc(y);
  1518.                val(copy(Inrec, p, y-p), timeused, a);
  1519.  
  1520.                getrec;
  1521.                val(copy(Inrec, 11, 2), houroff, a);
  1522.                if houroff > 23 then
  1523.                   houroff := houroff - 24;
  1524.                val(copy(Inrec, 14, 2), minutoff, a);
  1525.  
  1526.                while timeused > 0 do
  1527.                   begin
  1528.                      if timeused > minutoff then
  1529.                         a := minutoff
  1530.                      else
  1531.                         a := timeused;
  1532.  
  1533.                      UsedMinutes := UsedMinutes + a;
  1534.                      while UsedMinutes > 60 do
  1535.                      begin
  1536.                         inc(Hours);
  1537.                         UsedMinutes := UsedMinutes - 60;
  1538.                      end;
  1539.  
  1540.                      Hrs[houroff] := Hrs[houroff]+a;
  1541.                      timeused := timeused-a;
  1542.  
  1543.                      if houroff > 0 then
  1544.                         dec(houroff)
  1545.                      else
  1546.                         houroff := 23;
  1547.                      minutoff := 60;
  1548.                   end;
  1549.             end
  1550.  
  1551.          else
  1552.             case Inrec[7] of
  1553.                '*' :;
  1554.  
  1555.                '(' : if inrec[9] <> ')' then inc(stuff)
  1556.                      else if inrec[8] = 'D' then indownload
  1557.                      else if inrec[8] = 'U' then indownload
  1558.                      else catchall;
  1559.  
  1560.                'A' : if pos('Access Denied', Inrec) > 0 then inc(tcan)
  1561.                      else if pos('ARC view', Inrec) > 0 then inc(arcview)
  1562.                      else if pos('Archive view', Inrec) > 0 then inc(arcview)
  1563.                      else if pos('ARC test', Inrec) > 0 then inc(arctest)
  1564.                      else if pos('ARCM exe', Inrec) > 0 then inc(arcmail)
  1565.                      else catchall;
  1566.  
  1567.                'B' : if pos('Bulletin Read:', Inrec) > 0 then bulletins
  1568.                      else if pos('Back from DOS', Inrec) > 0 then inc(backdos)
  1569.                      else catchall;
  1570.  
  1571.                'C' : if pos('Comment ', Inrec) > 0 then inc(comments)
  1572.                      else if pos('Caller Exited to DOS ', Inrec) > 0 then DOSdrop
  1573.                      else catchall;
  1574.  
  1575.                'D' : if pos('Directory Scan ', Inrec) > 0 then inc(dirscan)
  1576.                      else catchall;
  1577.  
  1578.                'E' : if pos('Extract ', Inrec) > 0 then inc(extarc)
  1579.                      else catchall;
  1580.  
  1581.                'F' : if pos('File (', Inrec) > 0 then inc(stuff)
  1582.                      else if pos('Free download', Inrec) > 0 then inc(free_down)
  1583.                      else catchall;
  1584.  
  1585.                'K' : if pos('Keyboard Time',Inrec) > 0 then inc(stuff)
  1586.                      else catchall;
  1587.  
  1588.                'I':  if pos('Insufficient ',Inrec) > 0 then inc(secviol)
  1589.                      else if pos('Invalid archive',Inrec) > 0 then inc(invalids)
  1590.                      else catchall;
  1591.  
  1592.                'M' : if pos('Left:', Inrec) > 0 then inc(mssgs)
  1593.                      else if pos('Killed:', Inrec) > 0 then inc(kills)
  1594.                      else catchall;
  1595.  
  1596.                'N' : if pos('Node CHAT ent', Inrec) > 0 then sysop_chat
  1597.                      else if pos('Node CHAT end', Inrec) > 0 then inc(stuff)
  1598.                      else catchall;
  1599.  
  1600.                'O' : if pos('Operator', Inrec) > 0 then inc(PAGE)
  1601.                      else if pos(' DOOR ', Inrec) > 0 then pdoors
  1602.                      else catchall;
  1603.  
  1604.                'P' : if pos('Password Failure (', Inrec) > 0 then inc(pwfail)
  1605.                      else if pos('PAKM exe', Inrec) > 0 then inc(arcmail)
  1606.                      else catchall;
  1607.  
  1608.                'R' : if pos('Refused', Inrec) > 0 then inc(refused)
  1609.                      else if pos('Registration', Inrec) > 0 then inc(new_guys)
  1610.                      else if pos('REARC ', Inrec) > 0 then inc(rearcs)
  1611.                      else if pos('REPAK ', Inrec) > 0 then inc(rearcs)
  1612.                      else catchall;
  1613.  
  1614.                'S' : if pos('Scheduled', Inrec) > 0 then inc(events)
  1615.                      else if pos('Sorry', Inrec) > 0 then inc(secviol)
  1616.                      else if pos('Sysop CHAT a', Inrec) > 0 then sysop_chat
  1617.                      else if pos('Sysop CHAT e', Inrec) > 0 then inc(stuff)
  1618.                      else catchall;
  1619.  
  1620.                'T' : if pos('Time Limit', Inrec) > 0 then inc(time_limit)
  1621.                      else if pos('TEST executed', Inrec) > 0 then inc(arctest)
  1622.                      else if pos('Thanks, ', Inrec) > 0 then inc(secviol)
  1623.                      else catchall;
  1624.  
  1625.                'V' : if pos('View ARC', Inrec) > 0 then inc(viewmember)
  1626.                      else if pos('View archive', Inrec) > 0 then inc(viewmember)
  1627.                      else catchall;
  1628.  
  1629.                '0'..'9':
  1630.                      if pos(' files,',Inrec) > 0 then batch
  1631.                      else if pos(' messages ',Inrec) > 0 then arcmsgs
  1632.                      else catchall;
  1633.  
  1634.             else catchall;
  1635.             end;
  1636.       end;
  1637.  
  1638.       tx1 := 'Working.... 100.0 %';
  1639.       print(3, 17, tx1, 12);
  1640.    end;
  1641.  
  1642.  
  1643. (* -------------------------------------------------------- *)
  1644.  
  1645. var
  1646.    line: string;
  1647.    xfd: text;
  1648.  
  1649. procedure write_list(node: ItemPointer);
  1650. begin
  1651.    while node <> nil do
  1652.    begin
  1653.       writeln(xfd,node^.name);
  1654.       writeln(xfd,node^.count);
  1655.       node := node^.next;
  1656.    end;
  1657.    writeln(xfd);
  1658. end;
  1659.  
  1660. procedure write_tree(node: FilePointer);
  1661. begin
  1662.    if node = nil then
  1663.       writeln(xfd)
  1664.    else
  1665.    begin
  1666.       writeln(xfd,node^.name);
  1667.       writeln(xfd,node^.size,' ',node^.count);
  1668.       write_tree(node^.higher);
  1669.       write_tree(node^.lower);
  1670.    end;
  1671. end;
  1672.  
  1673.  
  1674. (* -------------------------------------------------------- *)
  1675.  
  1676. procedure read_list(var node: ItemPointer);
  1677. var
  1678.    add:  ItemPointer;
  1679.  
  1680. begin
  1681.    {special case - empty list}
  1682.    readln(xfd,line);
  1683.    if length(line) = 0 then
  1684.    begin
  1685.       node := nil;
  1686.       exit;
  1687.    end;
  1688.  
  1689.    {insert head of list}
  1690.    new(node);
  1691.    add := node;
  1692.    add^.name := line;
  1693.    readln(xfd,add^.count);
  1694.  
  1695.    {add rest of the list}
  1696.    readln(xfd,line);
  1697.    while length(line) <> 0 do
  1698.    begin
  1699.       new(add^.next);
  1700.       add := add^.next;
  1701.       add^.name := line;
  1702.       readln(xfd,add^.count);
  1703.  
  1704.       readln(xfd,line);
  1705.    end;
  1706.  
  1707.    add^.next := nil;
  1708. end;
  1709.  
  1710.  
  1711. procedure read_tree(var node: FilePointer);
  1712. begin
  1713.    readln(xfd,line);
  1714.    if length(line)=0 then
  1715.       node := nil
  1716.    else
  1717.    begin
  1718.       new(node);
  1719.       node^.name := line;
  1720.       read(xfd,node^.size);
  1721.       readln(xfd,node^.count);
  1722.       read_tree(node^.higher);
  1723.       read_tree(node^.lower);
  1724.    end;
  1725. end;
  1726.  
  1727.  
  1728. (* -------------------------------------------------------- *)
  1729. procedure save_state;
  1730. var
  1731.    i: integer;
  1732.  
  1733. begin
  1734.    gotoxy(1, 1);
  1735.    write('Writing CALLS.SAV...');
  1736.  
  1737.    assign(xfd,'calls.sav');
  1738.    rewrite(xfd);
  1739.  
  1740.    writeln(xfd,'-4');
  1741.    writeln(xfd,
  1742.            spare1,' ',  spare2,' ',
  1743.            spare3,' ',  spare4,' ',
  1744.            spare5,' ',  spare6,' ',
  1745.            spare7,' ',  spare8,' ',
  1746.            spare9,' ',  spare10);
  1747.    writeln(xfd,
  1748.            arcmail,' ', msgcount,' ',
  1749.            invalids,' ',mins_dn,' ',
  1750.            mins_up,' ', mins_schat,' ',
  1751.            nchat,' ',   mins_nchat,' ',
  1752.            arctest,' ', free_down);
  1753.    writeln(xfd,
  1754.            arcview,' ',      B1200,' ',
  1755.            B19200,' ',       B2400,' ',
  1756.            B300,' ',         B9600,' ',
  1757.            backdos,' ',      batchs);
  1758.    writeln(xfd,
  1759.            Blocal,' ',       blts,' ',
  1760.            caller,' ',       schat,' ',
  1761.            comments,' ',     dirscan,' ',
  1762.            DOORs,' ',        DosTime);
  1763.    writeln(xfd,
  1764.            DosTimes,' ',     down,' ',
  1765.            d_abort,' ',      events,' ',
  1766.            even_parity,' ',  extarc,' ',
  1767.            graphics,' ',     Hours);
  1768.    writeln(xfd,
  1769.            joins,' ',        kills,' ',
  1770.            lockouts,' ',     UsedMinutes,' ',
  1771.            mssgs,' ',        new_guys,' ',
  1772.            non_graphics,' ', PAGE);
  1773.    writeln(xfd,
  1774.            pwfail,' ',       question,' ',
  1775.            rearcs,' ',       refused,' ',
  1776.            secviol,' ',      stuff,' ',
  1777.            sysop_local,' ',  sysop_remote);
  1778.    writeln(xfd,
  1779.            tcan,' ',         time_limit,' ',
  1780.            TotHours:0:2,' ', UniqFiles,' ',
  1781.            up,' ',           u_abort,' ',
  1782.            viewmember);
  1783.  
  1784.    writeln(xfd,copy(first_rec,1,62));
  1785.  
  1786.    for i := 1 to ProtocolCount do
  1787.    with Protocol[i] do
  1788.       writeln(xfd,
  1789.                  code,' ',
  1790.                  Uploads,' ',
  1791.                  UpTime:0:2,' ',
  1792.                  UpIdeal:0:2,' ',
  1793.                  Downloads,' ',
  1794.                  DownTime:0:2,' ',
  1795.                  DownIdeal:0:2);
  1796.  
  1797.    for i := 0 to 23 do
  1798.       writeln(xfd,Hrs[i]);
  1799.  
  1800.    write_list(FirstBatch);
  1801.    write_list(FirstBullet);
  1802.    write_list(FirstConf);
  1803.    write_list(FirstDoor);
  1804.    write_tree(FileTree);
  1805.  
  1806.    close(xfd);
  1807.    writeln(^M'                        ');
  1808. end;
  1809.  
  1810.  
  1811. (* -------------------------------------------------------- *)
  1812. procedure load_state;
  1813. var
  1814.    i: integer;
  1815.    c: char;
  1816.  
  1817. begin
  1818.    assign(xfd,'calls.sav');
  1819.    {$i-} reset(xfd); {$i+}
  1820.    if ioresult <> 0 then
  1821.       exit;
  1822.  
  1823.    gotoxy(1, 1);
  1824.    writeln('Loading CALLS.SAV...');
  1825.  
  1826.    read(xfd,filever);
  1827.    if filever <> -4 then
  1828.    begin
  1829.       writeln('Can''t use your old CALLS.SAV file!  Will create a new one.');
  1830.       close(xfd);
  1831.       exit;
  1832.    end;
  1833.  
  1834.    read(xfd,
  1835.            spare1,      spare2,
  1836.            spare3,      spare4,
  1837.            spare5,      spare6,
  1838.            spare7,      spare8,
  1839.            spare9,      spare10);
  1840.    read(xfd,
  1841.            arcmail,     msgcount,
  1842.            invalids,    mins_dn,
  1843.            mins_up,     mins_schat,
  1844.            nchat,       mins_nchat,
  1845.            arctest,     free_down);
  1846.    read(xfd,
  1847.            arcview,      B1200,
  1848.            B19200,       B2400,
  1849.            B300,         B9600,
  1850.            backdos,      batchs);
  1851.    read(xfd,
  1852.            Blocal,       blts,
  1853.            caller,       schat,
  1854.            comments,     dirscan,
  1855.            DOORs,        DosTime);
  1856.    read(xfd,
  1857.            DosTimes,     down,
  1858.            d_abort,      events,
  1859.            even_parity,  extarc,
  1860.            graphics,     Hours);
  1861.    read(xfd,
  1862.            joins,        kills,
  1863.            lockouts,     UsedMinutes,
  1864.            mssgs,        new_guys,
  1865.            non_graphics, PAGE);
  1866.    read(xfd,
  1867.            pwfail,       question,
  1868.            rearcs,       refused,
  1869.            secviol,      stuff,
  1870.            sysop_local,  sysop_remote);
  1871.    readln(xfd,
  1872.            tcan,         time_limit,
  1873.            TotHours,     UniqFiles,
  1874.            up,           u_abort,
  1875.            viewmember);
  1876.  
  1877.    readln(xfd,first_rec);
  1878.  
  1879.    repeat
  1880.       read(xfd,c);
  1881.  
  1882.       i := 1;
  1883.       while (i < ProtocolCount) and 
  1884.             (c <> Protocol[i].Code) and
  1885.             (Protocol[i].Code <> '?') do
  1886.          inc(i);
  1887.  
  1888.       with Protocol[i] do
  1889.          readln(xfd,Uploads,
  1890.                     UpTime,
  1891.                     UpIdeal,
  1892.                     Downloads,
  1893.                     DownTime,
  1894.                     DownIdeal);
  1895.    until c = '?';
  1896.  
  1897.    for i := 0 to 23 do
  1898.       readln(xfd,Hrs[i]);
  1899.  
  1900.    read_list(FirstBatch);
  1901.    read_list(FirstBullet);
  1902.    read_list(FirstConf);
  1903.    read_list(FirstDoor);
  1904.    read_tree(FileTree);
  1905.  
  1906.    close(xfd);
  1907.    writeln(^M'                        ');
  1908. end;
  1909.  
  1910.  
  1911.  
  1912. (* -------------------------------------------------------- *)
  1913.  
  1914. procedure load_dirs;
  1915. var
  1916.    fd:   text;
  1917.  
  1918. begin
  1919.    search_dirs := 0;
  1920. (***
  1921.    assign(fd,'calls.dir');
  1922.    {$i-} reset(fd); {$i+}
  1923.    if ioresult <> 0 then
  1924.    begin
  1925.       writeln('Warning: CALLS.DIR is missing.');
  1926.       exit;
  1927.    end;
  1928.  
  1929.    while not eof(fd) do
  1930.    begin
  1931.       inc(search_dirs);
  1932.       readln(fd,search_dir[search_dirs]);
  1933.    end;
  1934.  
  1935.    close(fd);
  1936. ***)
  1937. end;
  1938.  
  1939. (* -------------------------------------------------------- *)
  1940.  
  1941. procedure init;            {initialize}
  1942.  
  1943.    begin
  1944.       {Initialize the variables}
  1945.       total_records := 0;
  1946.       first_record := 0;
  1947.       viewmember := 0;
  1948.       extarc := 0;
  1949.       rearcs := 0;
  1950.       arctest := 0;
  1951.       arcview := 0;
  1952.       B1200 := 0;
  1953.       B19200 := 0;
  1954.       B2400 := 0;
  1955.       B300 := 0;
  1956.       B9600 := 0;
  1957.       backdos := 0;
  1958.       batchs := 0;
  1959.       baud := 0;
  1960.       Blocal := 0;
  1961.       blts := 0;
  1962.       caller := 0;
  1963.       schat := 0;
  1964.       comments := 0;
  1965.       dirscan := 0;
  1966.       DOORs := 0;
  1967.       DosTime := 0;
  1968.       DosTimes := 0;
  1969.       down := 0;
  1970.       d_abort := 0;
  1971.       elapsed_time := 0;
  1972.       Endtime := 0;
  1973.       events := 0;
  1974.       even_parity := 0;
  1975.       free_down := 0;
  1976.       graphics := 0;
  1977.       Hours := 0;
  1978.       joins := 0;
  1979.       kills := 0;
  1980.       lockouts := 0;
  1981.       logsize := 0;
  1982.       UsedMinutes := 0;
  1983.       mssgs := 0;
  1984.       new_guys := 0;
  1985.       non_graphics := 0;
  1986.       PAGE := 0;
  1987.       pwfail := 0;
  1988.       question := 0;
  1989.       refused := 0;
  1990.       secviol := 0;
  1991.       start_time := 0;
  1992.       stuff := 0;
  1993.       sysop_local := 0;
  1994.       sysop_remote := 0;
  1995.       tcan := 0;
  1996.       time_limit := 0;
  1997.       TotHours := 0;
  1998.       UniqFiles := 0;
  1999.       up := 0;
  2000.       u_abort := 0;
  2001.       min_download := 0;
  2002.       msgcount := 0;
  2003.       arcmail := 0;
  2004.       invalids := 0;
  2005.       mins_dn := 0;
  2006.       mins_up := 0;
  2007.       mins_schat := 0;
  2008.       nchat := 0;
  2009.       mins_nchat := 0;
  2010.       spare1 := 0; spare2 := 0; spare3 := 0; spare4 := 0; spare5 := 0;
  2011.       spare6 := 0; spare7 := 0; spare8 := 0; spare9 := 0; spare10 := 0;
  2012.  
  2013.       PeriodCovered := '';
  2014.       reports := '';
  2015.       first_rec := '';
  2016.  
  2017.       FileTree := nil;
  2018.       FirstBatch := nil;
  2019.       FirstBullet := nil;
  2020.       FirstConf := nil;
  2021.       FirstDoor := nil;
  2022.  
  2023.       fillchar(Hrs, sizeof(Hrs), 0);
  2024.       elapsed_time := 0;
  2025.       start_time := Time;
  2026.  
  2027.  
  2028.       {provide command-line defaults}
  2029.       outfile := 'CALLFILE.DOC';
  2030.       reports := 'ANBCDEFGHIJKLM';
  2031.       min_download := 2;
  2032.                    {          1         2   }
  2033.                    {012345678901234567890123}
  2034.       PeakTable := 'YNNNNNNNNNNNNNNNNYYYYYYY';
  2035.  
  2036.       if paramcount < 1 then
  2037.          begin
  2038.             assign(output,'');   {make redirection work so the usage}
  2039.             rewrite(output);     {can be captured in a file}
  2040.  
  2041.             writeln;
  2042.             writeln('Usage:    calls callers-file output-file report-list min-downloads peak-hours');
  2043.             writeln;
  2044.             writeln('callers-file is your pcboard CALLER file');
  2045.             writeln('output-file  defaults to ',outfile);
  2046.             writeln('report-list  defaults to ',reports);
  2047.             writeln('min-download defaults to ',min_download);
  2048.             writeln;
  2049.             writeln('peak-hours   defaults to ',PeakTable);
  2050.             writeln('                        {0         1         2   }');
  2051.             writeln('                        {012345678901234567890123}');
  2052.             writeln('Examples:');
  2053.             writeln('  calls \pcb\main\caller \gen\blt3');
  2054.             writeln('  calls \pcb\main\caller \gen\blt3 ABCEFG 4 NNNNNNNNYYYYYYYYYNNNNNNN');
  2055.             writeln;
  2056.             writeln('The legal report-list letters are:');
  2057.             writeln('   A: system statistics            B: graphic modes');
  2058.             writeln('   C: baud rates                   D: hourly usage');
  2059.             writeln('   E: conferences joined           F: bulletins read');
  2060.             writeln('   G: doors opened                 H: download protocols');
  2061.             writeln('   I: download efficiency          J: upload protocols');
  2062.             writeln('   K: upload efficiency            L: batch sizes');
  2063.             writeln('   M: files downloaded             N: security statistics');
  2064.             writeln('                                   Z: insert a blank line');
  2065.             halt;
  2066.          end;
  2067.  
  2068.       if paramcount > 1 then
  2069.          outfile := paramstr(2);
  2070.       if paramcount > 2 then
  2071.          reports := paramstr(3);
  2072.       if paramcount > 3 then
  2073.          val(paramstr(4),min_download,total_records);
  2074.       if paramcount > 4 then
  2075.          PeakTable := paramstr(5);
  2076.  
  2077.       clrscr;
  2078.       print(13,  5, '╔═════════════════════════════════════════════════════╗', lightred);
  2079.       print(13,  6, '║                                                     ║', lightred);
  2080.       print(13,  7, '║                                                     ║', lightred);
  2081.       print(13,  8, '║                                                     ║', lightred);
  2082.       print(13,  9, '║                                                     ║', lightred);
  2083.       print(13, 10, '║                                                     ║', lightred);
  2084.       print(13, 11, '║                                                     ║', lightred);
  2085.       print(13, 12, '║                                                     ║', lightred);
  2086.       print(13, 13, '║                                                     ║', lightred);
  2087.       print(13, 14, '║                                                     ║', lightred);
  2088.       print(13, 15, '╚═════════════════════════════════════════════════════╝', lightred);
  2089.  
  2090.       print(32, 7, pcbversion, lightgreen);
  2091.       print(30, 9, 'Calls v'+version+', '+reldate, lightgreen);
  2092.       print(29, 11, '(c) 1987  Warren Lauzon', lightcyan);
  2093.       {print(18, 11, 'SYSOP, Phoenix Techline PCBoard, 602/936-3058', yellow);}
  2094.       print(20, 13, 'Supported by The Tool Shop, 602/279-2673',white);
  2095.       gotoxy(1,1);
  2096.  
  2097.    end;
  2098.  
  2099.  
  2100. (* -------------------------------------------------------- *)
  2101. begin
  2102.    init;
  2103.    load_state;
  2104.    load_dirs;
  2105.    openfiles;
  2106.    scanfile;
  2107.  
  2108.    Endtime := Time;
  2109.    elapsed_time := Endtime-start_time;
  2110.    gotoxy(30, 17);
  2111.    writeln('Elapsed Time:  ', elapsed_time : 6 : 1);
  2112.  
  2113.    output_results;
  2114.    save_state;
  2115.    gotoxy(1, 25);
  2116. end.
  2117.  
  2118.